/**
 * Copyright (c), 上海沃恩信息科技有限公司.
 * All rights reserved.
 * Licensed under BSD (https://www.pittypat.work/bsd.html).
 */

package com.waln.authority.authentication;

import java.beans.PropertyVetoException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.Base64;

import com.waln.authority.authentication.args.Demand;
import com.waln.authority.authentication.args.Login;
import com.waln.authority.authentication.args.Logout;

import pittypat.FunctionModel;
import pittypat.IAsyncProgress;
import pittypat.IAuthorityService;
import pittypat.LoginResult;
import pittypat.NavList;
import pittypat.Permission;
import pittypat.configuration.ConfigException;

/**
 * 用户验证服务。
 */
public final class AuthorityService implements IAuthorityService {
	private Api api;

	/**
	 * 初始化 AuthorityService 类的新实例。
	 */
	public AuthorityService() {
		this.api = new Api();
	}

	/**
	 * 获取当前系统在目标授权服务中的系统令牌。
	 * 
	 * @param systemId
	 *            系统的 Id。
	 * @param systemKey
	 *            系统的密钥。
	 * @param progress
	 *            跟踪和汇报异步操作的进度。
	 * @return 系统令牌。
	 */
	@Override
	public String getSystemToken(String systemId, String systemKey, IAsyncProgress progress) {
		return "";
	}

	/**
	 * 使用指定的用户名和密码登录当前系统。
	 * 
	 * @param systemToken
	 *            系统令牌。
	 * @param loginName
	 *            用户登录名称。
	 * @param password
	 *            用户登录密码的明文。
	 * @param progress
	 *            跟踪和汇报异步操作的进度。
	 * @return 如果登录成功，则返回用户令牌，否则返回 null 或空字符串。
	 * @throws PropertyVetoException
	 * @throws ConfigException
	 * @throws SQLException
	 * @throws SecurityException
	 * @throws NoSuchMethodException
	 * @throws InvocationTargetException
	 * @throws UnsupportedEncodingException
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 */
	@Override
	public LoginResult login(String systemToken, String loginName, String password, IAsyncProgress progress)
			throws IllegalArgumentException, IllegalAccessException, InstantiationException, ClassNotFoundException,
			UnsupportedEncodingException, InvocationTargetException, NoSuchMethodException, SecurityException,
			SQLException, ConfigException, PropertyVetoException {
		if (loginName == null || loginName.length() == 0 || password == null || password.length() == 0) {
			return LoginResult.ANONYMOUS;
		}

		FunctionModel<Login> model = new FunctionModel<Login>(Login.class);
		model.getArgs().name = loginName;
		model.getArgs().password = password;

		this.api.login(model, progress);

		if (model.isSuccess() && model.getArgs().user != null && model.getArgs().user.id != null
				&& model.getArgs().token != null && model.getArgs().token.length > 0) {
			return new LoginResult(new AuthorityUser(model.getArgs().user),
					Base64.getEncoder().encodeToString(model.getArgs().token));
		}

		return LoginResult.ANONYMOUS;
	}

	/**
	 * 注销指定令牌的用户。
	 * 
	 * @param systemToken
	 *            系统令牌。
	 * @param userToken
	 *            要注销的用户的用户令牌。
	 * @param progress
	 *            跟踪和汇报异步操作的进度。
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 * @throws PropertyVetoException
	 * @throws ConfigException
	 * @throws SQLException
	 * @throws SecurityException
	 * @throws NoSuchMethodException
	 * @throws InvocationTargetException
	 * @throws UnsupportedEncodingException
	 * @throws ClassNotFoundException
	 * @throws IllegalArgumentException
	 */
	@Override
	public void logout(String systemToken, String userToken, IAsyncProgress progress)
			throws InstantiationException, IllegalAccessException, IllegalArgumentException, ClassNotFoundException,
			UnsupportedEncodingException, InvocationTargetException, NoSuchMethodException, SecurityException,
			SQLException, ConfigException, PropertyVetoException {
		if (userToken != null && userToken.length() > 0) {
			FunctionModel<Logout> model = new FunctionModel<Logout>(Logout.class);
			model.getArgs().token = Base64.getDecoder().decode(userToken);

			this.api.logout(model, progress);
		}
	}

	/**
	 * 验证指定的用户是否对指定路径的功能具有权限。
	 * 
	 * @param systemToken
	 *            系统令牌。
	 * @param userToken
	 *            用户令牌。
	 * @param funcPath
	 *            目标功能的完整路径。当传递空引用或空字符串时，用于返回指定令牌的用户的用户信息。
	 * @param progress
	 *            跟踪和汇报异步操作的进度。
	 * @return 返回作为验证结果的用户和授权信息，如果返回空引用，则使用未授权的匿名用户。
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 * @throws PropertyVetoException
	 * @throws ConfigException
	 * @throws SQLException
	 * @throws SecurityException
	 * @throws NoSuchMethodException
	 * @throws InvocationTargetException
	 * @throws UnsupportedEncodingException
	 * @throws ClassNotFoundException
	 * @throws IllegalArgumentException
	 */
	@Override
	public Permission demand(String systemToken, String userToken, String funcPath, IAsyncProgress progress)
			throws InstantiationException, IllegalAccessException, IllegalArgumentException, ClassNotFoundException,
			UnsupportedEncodingException, InvocationTargetException, NoSuchMethodException, SecurityException,
			SQLException, ConfigException, PropertyVetoException {
		if (userToken == null || userToken.length() == 0) {
			return null;
		}

		FunctionModel<Demand> model = new FunctionModel<Demand>(Demand.class);
		model.getArgs().token = Base64.getDecoder().decode(userToken);
		model.getArgs().path = funcPath;

		this.api.demand(model, progress);

		if (!model.isSuccess() || model.getArgs().user == null) {
			return null;
		}

		return new Permission(new AuthorityUser(model.getArgs().user), model.getArgs().authorized);
	}

	/**
	 * 加载指定用户拥有权限的所有 App 和模块的列表，也就是导航列表。
	 * 
	 * @param systemToken
	 *            系统令牌。
	 * @param userToken
	 *            用户令牌。
	 * @param progress
	 *            跟踪和汇报异步操作的进度。
	 * @return 指定用户拥有权限的 App 和模块的导航列表。
	 * @throws PropertyVetoException
	 * @throws ConfigException
	 * @throws SQLException
	 * @throws SecurityException
	 * @throws NoSuchMethodException
	 * @throws InvocationTargetException
	 * @throws UnsupportedEncodingException
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 */
	@Override
	public NavList navList(String systemToken, String userToken, IAsyncProgress progress)
			throws IllegalArgumentException, IllegalAccessException, InstantiationException, ClassNotFoundException,
			UnsupportedEncodingException, InvocationTargetException, NoSuchMethodException, SecurityException,
			SQLException, ConfigException, PropertyVetoException {
		if (userToken == null || userToken.length() == 0) {
			return NavList.EMPTY;
		}

		FunctionModel<com.waln.authority.authentication.args.NavList> model = new FunctionModel<>(
				com.waln.authority.authentication.args.NavList.class);
		model.getArgs().token = Base64.getDecoder().decode(userToken);

		this.api.navList(model, progress);

		if (!model.isSuccess()) {
			return NavList.EMPTY;
		}

		return NavApp.toNavApps(model.getArgs().apps, model.getArgs().modules);
	}
}
